// STUNClient.cpp: implementation of the CTurnClient class.
//
//////////////////////////////////////////////////////////////////////

#include "TurnClient.h"
/*
#ifndef WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
*/
#include "mysocket.h"
#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#include <string.h>
#include <errno.h>
#endif
#include "osplatform.h"
#include "TurnMessage.h"
#include "Log.h"
#include "MD5Stream.h"
#ifdef USE_DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define TRY_TIMES	3
bool ComputeMD5(const char *pinput,int len,char *poutput);
#ifdef IPV6_SUPPORT
	#define SS_GET_PORT(ssp) (((struct sockaddr_in*)(ssp))->sin_port)
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTurnClient::CTurnClient()
{
#ifndef IPV6_SUPPORT
	m_tls = socket(AF_INET,SOCK_STREAM,0);
#else/* for protocol independent, should use getaddrinfo depend on m_server address */
	m_tls = socket(AF_INET6,SOCK_STREAM,0);
#endif
	m_s = INVALID_SOCKET;
	m_nTimeout = 2000;
	m_nAllocIP = 0;
	m_nAllocPort = 0;
	m_nNATIP = 0;
	m_nNATPort = 0;
	m_nSourceIP = 0;
	m_nSourcePort = 0;
	m_nLifeTime = 120;//120 seconds
	m_bAllocateOK = false;
	m_nErrorCount = 0;
	m_nDeltaTime = 2000;
	m_nNextTime = 0;
	m_nStartTime = 0;
	m_nStopTime = 0;
	m_nTryCount = 0;

	m_bAllocate = FALSE;
	m_bAllocateRelay = FALSE;
}

CTurnClient::CTurnClient(const char *ip,unsigned short port)
{
	m_nErrorCount= 0;
#ifndef IPV6_SUPPORT
	m_tls = socket(AF_INET,SOCK_STREAM,0);
#else
	m_tls = socket(AF_INET6,SOCK_STREAM,0);
#endif
	if(m_tls == INVALID_SOCKET)
	{
		Loger.printf(LOG_MSG,"TurnClient create socket TLS error %s\r\n",strerror(errno));
	}

#ifndef IPV6_SUPPORT	
	m_s = socket(AF_INET,SOCK_DGRAM,0);
	m_nTimeout = 2000;
	sockaddr_in addr;
	
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(ip);
	if(port > 0)
	{
		addr.sin_port = htons(port);
		m_nLocalPort = port;
	}
	else
	{
		srand(time(NULL));
		int m = rand()%65535;		
		for(int i=30000;i<65535;i++)
		{
			addr.sin_family = AF_INET;
			addr.sin_addr.s_addr = inet_addr(ip);
			addr.sin_port = htons(m);
			if(bind(m_s,(sockaddr *)&addr,sizeof(addr)) != -1)
			{
				m_nLocalPort = m;
				break;
			}
			m++;
			if(m > 65535)
				m = 30000;
		}
	}
#else
	struct addrinfo aiHint, *res;
	int error;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_socktype = SOCK_DGRAM;
	aiHint.ai_flags = AI_NUMERICHOST;
	error = getaddrinfo(ip, NULL, &aiHint, &res);
	m_s = socket(res->ai_family, res->ai_socktype, 0);
	m_nTimeout = 2000;
	if(port > 0)
	{
		SS_GET_PORT(res->ai_addr) = htons(port);
		m_nLocalPort = port;
	}else
	{
		srand(time(NULL));
		int m = rand() % 65535;
		for(int i=30000; i< 65535; i++)
		{
			SS_GET_PORT(res->ai_addr) = htons(m);
			if(bind(m_s, (sockaddr*)res->ai_addr, res->ai_addrlen) != -1)
			{
				m_nLocalPort = m;
				break;
			}
			m++;
			if(m > 65535)
				m = 30000;
		}
	}		
	freeaddrinfo(res);
#endif
	m_strLocalIP = ip;
	m_nNextTime = 0;
	m_nTryCount = 0;
	m_nAllocIP = 0;
	m_nAllocPort = 0;
	m_nNATIP = 0;
	m_nNATPort = 0;
	m_nSourceIP = 0;
	m_nSourcePort = 0;
	m_nServerPort = port;
	m_nLifeTime = 120;//120 seconds
	m_nDeltaTime = 2000;
	m_bAllocateOK = false;

	m_bAllocate = FALSE;
	m_bAllocateRelay = FALSE;

}
CTurnClient::~CTurnClient()
{
	if(m_s != INVALID_SOCKET)
	{
		FreeAllocateSocket();
		closesocket(m_s);
	}
	if(m_tls != INVALID_SOCKET)
	{
		closesocket(m_tls);
	}
}

int CTurnClient::TestNATType()
{
	sockaddr_in addr;
	socklen_t socklen;
	fd_set rset,set;
	timeval tv;
	char buffer[1024*2];
	char id[16];
	sockaddr_in changedaddress;
	sockaddr_in test1mapaddr;
	int n,len,type = 0;
	CTurnMessage pro;	
	
	if(m_strServerIP.empty() || m_nServerPort == 0)
		return STUN_ERROR;
	
	if(m_s == INVALID_SOCKET)
	{
		closesocket(m_s);		
		return STUN_ERROR;
	}	

	//test1
	pro.GeneralID(id);
	FD_ZERO(&set);
	FD_SET(m_s,&set);
	unsigned long nexttime,cur;
	tv.tv_sec = 1;
	tv.tv_usec = 0;
	int c = 0;
	int step = 0;
	bool ipsame = false;
	int status = 0;
	memset(&changedaddress,0,sizeof(sockaddr_in));
	gettimeofday(&tv,0);
	nexttime = tv.tv_sec * 1000 + tv.tv_usec/1000;
	while(1)
	{
		gettimeofday(&tv,0);
		cur = tv.tv_sec * 1000 + tv.tv_usec/1000;
		if(cur >= nexttime)
		{
			if(status == 0)
			{//send test1
				if(c >= 9)
				{//rfc3489 page 17, 
					if(step == 0)
					{
						type = STUN_UDPBLOCKED;
						break;
					}
					else 
					{
						type = STUN_SYMMETRIC;
						break;
					}
				}
				pro.Clear();
				pro.SetCommand(STUN_COMMAND_BIND_REQUEST);
				pro.SetTransactionID(id);
				n = pro.Encode(buffer,1024*2);
				if(step == 0 || changedaddress.sin_port == 0)
				{
					addr.sin_family = AF_INET;
					addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
					addr.sin_port = htons(m_nServerPort);//3478);
					len = sendto(m_s,buffer,n,0,(sockaddr *)&addr,sizeof(addr));
				}
				else
					len = sendto(m_s,buffer,n,0,(sockaddr *)&changedaddress,sizeof(addr));

				if(len != n)
				{
					type = STUN_ERROR;
					break;
				}
				nexttime += 100<<c;
				c++;
			}
			else if(status == 1)
			{//send test2
				if(c >= 9)
				{//rfc3489 page 17, 
					if(ipsame)
					{
						type = STUN_SYMMETRIC;
						break;
					}
					else
					{
						step++;
						//to test1
						status = 0;
						gettimeofday(&tv,0);
						nexttime = tv.tv_sec * 1000 + tv.tv_usec/1000;
						c = 0;
						continue;
					}
				}
				pro.Clear();
				pro.AddChangeRequest(new CChangeRequest(ChangeIpFlag|ChangePortFlag));
				pro.SetCommand(STUN_COMMAND_BIND_REQUEST);
				n = pro.Encode(buffer,1024*2);
				addr.sin_family = AF_INET;
				addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
				addr.sin_port = htons(m_nServerPort);//3478);
				len = sendto(m_s, buffer,n,0,(sockaddr *)&addr,sizeof(addr));
				if(len != n)
				{
					type = STUN_ERROR;
					break;
				}
				nexttime += 100<<c;
				c++;
			}
			else if(status == 2)
			{//send test3
				if(c >= 9)
				{//rfc3489 page 17, 
					type = STUN_PORT_RESTRICTED_CONE;
					break;
				}
				pro.Clear();
				pro.AddChangeRequest(new CChangeRequest(ChangePortFlag));
				pro.SetCommand(STUN_COMMAND_BIND_REQUEST);
				n = pro.Encode(buffer,1024*2);
				addr.sin_family = AF_INET;
				addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
				addr.sin_port = htons(m_nServerPort);//3478);
				len = sendto(m_s, buffer,n,0,(sockaddr *)&addr,sizeof(addr));
				if(len != n)
				{
					type = STUN_ERROR;
					break;
				}
				nexttime += 100<<c;
				c++;
			}
			else if(status == 3)
			{//send test4
			}
		}
		if(nexttime > cur)
		{
			tv.tv_sec = (nexttime - cur)/1000;
			tv.tv_usec = ((nexttime - cur)%1000)*1000;
		}
		else
		{
			tv.tv_sec = 0;
			tv.tv_usec = 10000;
		}
		rset = set;		
		n = select(m_s+1,&rset,NULL,NULL,&tv);
		if(n == 0)
		{
			c++;
			continue;
		}
		socklen = sizeof(addr);
		n = recvfrom(m_s,buffer,1024*2,0,(sockaddr *)&addr,&socklen);
		if(n > 0)
		{
			if(pro.Parse(buffer,n) == false)
			{
				type = STUN_ERROR;
				break;
			}
			if(status == 0)
			{//test1 response
				if(pro.GetCommand() != STUN_COMMAND_BIND_RESPONSE)
				{
					type = STUN_ERROR;
					break;
				}
				socklen = sizeof(addr);
				n = getsockname(m_s,(sockaddr *)&addr,&socklen);
				const CChangedAddress *pca = pro.GetChangedAddress();
				if(pca)
				{
					changedaddress.sin_family = AF_INET;
					changedaddress.sin_addr.s_addr = htonl(pca->GetIPV4());
					changedaddress.sin_port = htons(pca->GetPort());
				}
				const CMappedAddress *pm = pro.GetMappedAddress();
				if(pm == NULL)
					continue;
				if(step == 0)
				{
					test1mapaddr.sin_addr.s_addr = htonl(pm->GetIPV4());
					test1mapaddr.sin_port = htons(pm->GetPort());
					if( test1mapaddr.sin_addr.s_addr == addr.sin_addr.s_addr && 
						test1mapaddr.sin_port == addr.sin_port)
					{//no nat						
						ipsame = true;
					}
					status = 1;//to test2
					gettimeofday(&tv,0);
					nexttime = tv.tv_sec * 1000 + tv.tv_usec/1000;
					c = 0;
				}
				else
				{
					if(htonl(pm->GetIPV4()) == test1mapaddr.sin_addr.s_addr && 
						htons(pm->GetPort()) == test1mapaddr.sin_port)
					{//to test3
						status = 2;//to test2
						gettimeofday(&tv,0);
						nexttime = tv.tv_sec * 1000 + tv.tv_usec/1000;
						c = 0;					
					}
					else
					{/*the same source ip address / port, result different mapped address */
						type = STUN_SYMMETRIC;
						break;
					}
				}
				step++;
			}
			else if(status == 1)
			{//test 2
				if(pro.GetCommand() != STUN_COMMAND_BIND_RESPONSE)
				{
					type = STUN_ERROR;
					break;
				}
				if(ipsame)
				{
					type = STUN_OPEN;
					break;//****************************
				}
				else
				{
					type = STUN_FULL_CONE;
					break;
				}
				step++;
			}
			else if(status == 2)
			{//test 3
				type = STUN_RESTRICTED_CONE;
				break;
			}
			else
			{			
				break;
			}
		}
		else
		{
#ifdef WIN32
			int error = WSAGetLastError();
#endif
		}		
	}
	return type;
}

bool CTurnClient::CreateSocketPair(SOCKET &dataSocket, SOCKET &controlSocket)
{
	dataSocket = INVALID_SOCKET;
	controlSocket = INVALID_SOCKET;

	return false;
}

int CTurnClient::SharedSecretRequest()
{
	char buf[1024];
	int n;
	if(m_tls == INVALID_SOCKET)
	{
		printf("SharedSecretRequest tls error\r\n");
		return -1;
	}
#ifndef IPV6_SUPPORT
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = 0;//inet_addr("192.168.4.117");//"60.191.239.209");//;
	addr.sin_port = htons(0);
//	int n = bind(m_tls,(sockaddr *)&addr,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());//"60.191.239.209");//;
	addr.sin_port = htons(m_nServerPort);
	n = connect(m_tls,(sockaddr *)&addr,sizeof(addr));
#else
	struct addrinfo aiHint, *res;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_flags = AI_NUMERICHOST;
	int error;
	error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
	if(error)
		return false;
	SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
	int n = connect(m_tls,(sockaddr *)res->ai_addr,res->ai_addrlen);
	freeaddrinfo(res);
#endif
	if(n == -1)
	{
#ifdef WIN32
		printf("SharedSecretRequest connect error %d\r\n",WSAGetLastError());
#else
		printf("SharedSecretRequest connect error %d\r\n",errno);
#endif
		socklen_t socklen = sizeof(addr);
		getsockname(m_tls,(sockaddr *)&addr,&socklen);
		return -1;
	}
	CTurnMessage msg;
	msg.SetCommand(STUN_COMMAND_SHARED_SECRET_REQUEST);
	msg.AddUserName(new CUserName(m_strUserName.c_str()));
	
	int len = msg.Encode(buf,1024);
	if(len <= 0)
	{
		printf("SharedSecretRequest encode error\r\n");
		return -1;
	}
	n = send(m_tls,buf,len,0);
	if(n == -1)
	{
		printf("SharedSecretRequest send error\r\n");
		return -1;	
	}
	n = tlsread(buf,1024);
	if(n < 0)
	{
		printf("SharedSecretRequest tlsread error\r\n");
		return n;
	}
	msg.Parse(buf,n);
	if(msg.GetNonce() == NULL || msg.GetRealm() == NULL)
	{
		printf("SharedSecretRequest getnonce =NULL error\r\n");
		return -3;
	}
	mystring nonce = msg.GetNonce()->GetNonce();
	mystring realm = msg.GetRealm()->GetRealm();
	
	msg.Clear();
	msg.SetCommand(STUN_COMMAND_SHARED_SECRET_REQUEST);
	msg.AddUserName(new CUserName(m_strUserName.c_str()));
	msg.AddRealm(new CRealm(realm.c_str()));
	msg.AddNonce(new CNonce(nonce.c_str()));
	MD5Stream md5;
	mystring str;
	str = nonce;
	str += ":";
	str += realm;
	str += ":";
	str += m_strUserName;
	str += ":";
	str += m_strPassword;
	md5 << str;
	str = md5.getHex();
	msg.AddMessageIntegrity(new CMessageIntegrity(str.c_str(),str.length()));

	len = msg.Encode(buf,1024);
	if(len <= 0)
	{
		printf("SharedSecretRequest encode 2 error\r\n");
		return -1;
	}
	n = send(m_tls,buf,len,0);
	if(n == -1)
	{
		printf("SharedSecretRequest send 2 error\r\n");
		return -1;
	}
	n = tlsread(buf,1024);
	if(n < 0)
	{
		printf("SharedSecretRequest tlsread 2 error\r\n");
		return n;
	}
	if(msg.Parse(buf,n) == false)
	{
		printf("SharedSecretRequest parse error\r\n");
		return -1;
	}
	if(msg.GetCommand() != STUN_COMMAND_SHARED_SECRET_RESPONSE || msg.GetUserName() == NULL || msg.GetPassword() == NULL)
	{
		printf("SharedSecretRequest getcommand = %d error\r\n",msg.GetCommand());
		return -1;
	}
	m_strTempUserName = msg.GetUserName()->GetUserName();
	m_strTempPassword = msg.GetPassword()->GetPassword();

	return 0;
}

int CTurnClient::tlsread(char *pbuf, int len)
{
	int n;
	CTurnMessage msg;
	fd_set rset;
	timeval tv;
	int ptr = 0;
	int c = 0;
	while(c<TRY_TIMES)
	{
		FD_ZERO(&rset);
		FD_SET(m_tls,&rset);
		tv.tv_sec = m_nDeltaTime/1000;
		tv.tv_usec = ((m_nDeltaTime)%1000)*1000;
		n = select(m_tls+1,&rset,NULL,NULL,&tv);
		if(n == 0)
		{
			c++;			
			continue;
		}
		else if(n < 0)
		{
			printf("select error %s\r\n",strerror(errno));
			return -1;
		}
		n = recv(m_tls,&pbuf[ptr],1,0);
		if(n > 0)
		{
			ptr+=n;			
			if(msg.Parse(pbuf,ptr))
				return ptr;
		}
		else
		{
			printf("recv error %s\r\n",strerror(errno));
			return -1;
		}
	}
	return -2;
}

bool CTurnClient::AllocateRequest(int livetime)
{
	if(m_s == INVALID_SOCKET)
		return false;

	sockaddr_in addr;	
	char sha[32];
	CTurnMessage msg;
	msg.SetCommand(TURN_COMMAND_ALLOCATE_REQUEST);
	msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
	msg.AddBandwidth(new CBandwidth(384));
	msg.AddLifeTime(new CLifeTime(livetime));
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	char buf[1024];
	int n,i;
	//memset(buf,0,1024);
	n = msg.Encode(buf,1024) - 36;

	memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());
	
	ComputeMD5(buf,n+m_strTempPassword.length(),sha);
	
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	n = msg.Encode(buf,1024);	

	m_nTryCount = 0;
	m_nNextTime = 0;

#ifdef IPV6_SUPPORT
	struct addrinfo aiHint, *res;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_flags = AI_NUMERICHOST;
	int error;
	error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
	if(error)
		return false;
	SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
#endif
	for(i=0;i<TRY_TIMES;i++)
	{
#ifndef IPV6_SUPPORT
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
		addr.sin_port = htons(m_nServerPort);
		int len = sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
#else
		int len = sendto(m_s,buf,n,0,(sockaddr *)res->ai_addr,res->ai_addrlen);
#endif
		fd_set rset;
		FD_ZERO(&rset);
		FD_SET(m_s,&rset);
		timeval tv;
		tv.tv_sec = m_nDeltaTime/1000;
		tv.tv_usec = (m_nDeltaTime%1000)*1000;
		n = select(m_s+1,&rset,NULL,NULL,&tv);
		if(n == 0)
		{	
			continue;
		}
		else if(n < 0)
		{
#ifdef IPV6_SUPPORT
			freeaddrinfo(res);
#endif
			return false;	
		}
		else
			break;
	}
#ifdef IPV6_SUPPORT
	freeaddrinfo(res);
#endif
	if(i >= TRY_TIMES && n <= 0)
		return false;
	socklen_t socklen = sizeof(addr);
#ifndef IPV6_SUPPORT
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&addr,&socklen);
#else
	struct sockaddr_storage ss;
	int sslen = sizeof(ss);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif
	if(n > 0)
	{
		if(msg.Parse(buf,n) && (msg.GetCommand() == TURN_COMMAND_ALLOCATE_RESPONSE ||
			msg.GetCommand() == TURN_COMMAND_ALLOCATE_ERROR_RESPONSE))
		{
			
			if(msg.GetCommand() == TURN_COMMAND_ALLOCATE_RESPONSE)
			{
				const CMappedAddress *pma = msg.GetMappedAddress();
				if(pma)
				{
		#ifndef IPV6_SUPPORT
					m_nAllocIP = pma->GetIPV4();
		#else
					m_AllocIPv6 = pma->GetIPv6();
		#endif
					m_nAllocPort = pma->GetPort();
				}
				const CSourceAddress *psa = msg.GetSourceAddress();
				if(psa)
				{
		#ifndef IPV6_SUPPORT
					m_nNATIP = psa->GetIPV4();
		#else
					m_nNATIP6 = psa->GetIPv6();
		#endif
					m_nNATPort = psa->GetPort();
				}
				if(msg.GetLifeTime())
					m_nLifeTime = msg.GetLifeTime()->GetLifeTime();
				else
					m_nLifeTime = livetime;
				
				m_bAllocateOK = true;
				timeval tv;
				gettimeofday(&tv,0);
				m_nNextTime = tv.tv_sec*1000 + tv.tv_usec/1000 + m_nLifeTime*1000*2/3;
				m_nTryCount=1;
				m_bAllocate = TRUE;
				return true;
			}
			else
			{
				return false;
			}
		}		
	}
	return false;	
}

void CTurnClient::FreeAllocateSocket()
{
	if(m_s == INVALID_SOCKET || m_strTempUserName.empty())
		return ;
	sockaddr_in addr;
	char sha[32];
	CTurnMessage msg;
	msg.SetCommand(TURN_COMMAND_ALLOCATE_REQUEST);
	msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
	msg.AddBandwidth(new CBandwidth(384));
	msg.AddLifeTime(new CLifeTime(0));
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	char buf[1024*2];
	int n,i;
	//memset(buf,0,1024);
	n = msg.Encode(buf,1024) - 36;
	memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());
		
	
	if(ComputeMD5(buf,n+m_strTempPassword.length(),sha) == false)
	{	
		return ;
	}
	
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	n = msg.Encode(buf,1024);
	if(n <= 0)
	{	
		return ;
	}
#ifdef IPV6_SUPPORT
	struct addrinfo aiHint, *res;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_flags = AI_NUMERICHOST;
	int error;
	error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
	if(error)
		return ;
	SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
#endif
	for(i=0;i<TRY_TIMES;i++)
	{
#ifndef IPV6_SUPPORT
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
		addr.sin_port = htons(m_nServerPort);
		int len = sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
#else
		int len = sendto(m_s,buf,n,0,(sockaddr *)res->ai_addr,res->ai_addrlen);
#endif
		if(len != n)
		{	
		//	n = WSAGetLastError();
			#ifdef IPV6_SUPPORT
				freeaddrinfo(res);
			#endif
			return ;
		}
		fd_set rset;
		FD_ZERO(&rset);
		FD_SET(m_s,&rset);
		timeval tv;
		tv.tv_sec = m_nDeltaTime/1000;
		tv.tv_usec = (m_nDeltaTime%1000)*1000;
		n = select(m_s+1,&rset,NULL,NULL,&tv);
		if(n == 0)
		{
			continue;
		}
		else if(n < 0)
		{
			#ifdef IPV6_SUPPORT
				freeaddrinfo(res);
			#endif
			return ;	
		}
		else
			break;
	}
#ifdef IPV6_SUPPORT
	freeaddrinfo(res);
#endif
	if(i >= TRY_TIMES && n <= 0)
		return ;
#ifndef IPV6_SUPPORT
	socklen_t socklen = sizeof(addr);
	n = recvfrom(m_s,buf,1024*2,0,(sockaddr *)&addr,&socklen);
#else
	struct sockaddr_storage ss;
	int sslen = sizeof(ss);
	n = recvfrom(m_s,buf,1024*2,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif
	if(n > 0)
	{
		if(msg.Parse(buf,n))
		{
			const CMappedAddress *pma = msg.GetMappedAddress();
			if(pma)
			{
		#ifndef IPV6_SUPPORT
				m_nAllocIP = pma->GetIPV4();
		#else
				m_AllocIPv6 = pma->GetIPv6();
		#endif
				m_nAllocPort = pma->GetPort();
			}
		}
	}
//	n=WSAGetLastError();
	closesocket(m_s);
	m_s = INVALID_SOCKET;
}


bool CTurnClient::AllocateRelayRequest(int livetime)
{
	if(m_s == INVALID_SOCKET)
		return false;

	sockaddr_in addr;	
	char sha[32];
	CTurnMessage msg;
	msg.SetCommand(TURN_COMMAND_ALLOCATE_RELAY_REQUEST);
	msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
	msg.AddBandwidth(new CBandwidth(384));
	msg.AddLifeTime(new CLifeTime(livetime));
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	char buf[1024];
	int n,i;
	//memset(buf,0,1024);
	n = msg.Encode(buf,1024) - 36;

	memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());
	
	ComputeMD5(buf,n+m_strTempPassword.length(),sha);
	
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	n = msg.Encode(buf,1024);	

	m_nTryCount = 0;
	m_nNextTime = 0;

#ifdef IPV6_SUPPORT
	struct addrinfo aiHint, *res;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_flags = AI_NUMERICHOST;
	int error;
	error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
	if(error)
		return false;
	SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
#endif
	for(i=0;i<TRY_TIMES;i++)
	{
#ifndef IPV6_SUPPORT
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
		addr.sin_port = htons(m_nServerPort);
		int len = sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
#else
		int len = sendto(m_s,buf,n,0,(sockaddr *)res->ai_addr,res->ai_addrlen);
#endif
		fd_set rset;
		FD_ZERO(&rset);
		FD_SET(m_s,&rset);
		timeval tv;
		tv.tv_sec = m_nDeltaTime/1000;
		tv.tv_usec = (m_nDeltaTime%1000)*1000;
		n = select(m_s+1,&rset,NULL,NULL,&tv);
		if(n == 0)
		{	
			continue;
		}
		else if(n < 0)
		{
#ifdef IPV6_SUPPORT
			freeaddrinfo(res);
#endif
			return false;	
		}
		else
			break;
	}
#ifdef IPV6_SUPPORT
	freeaddrinfo(res);
#endif
	if(i >= TRY_TIMES && n <= 0)
		return false;
	socklen_t socklen = sizeof(addr);
#ifndef IPV6_SUPPORT
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&addr,&socklen);
#else
	struct sockaddr_storage ss;
	int sslen = sizeof(ss);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif
	if(n > 0)
	{
		if(msg.Parse(buf,n) && (msg.GetCommand() == TURN_COMMAND_ALLOCATE_RELAY_RESPONSE ||
			msg.GetCommand() == TURN_COMMAND_ALLOCATE_RELAY_ERROR_RESPONSE))
		{
			if(msg.GetCommand() == TURN_COMMAND_ALLOCATE_RELAY_RESPONSE)
			{
				const CMappedAddress *pma = msg.GetMappedAddress();
				if(pma)
				{
		#ifndef IPV6_SUPPORT
					m_nAllocIP = pma->GetIPV4();
		#else
					m_AllocIPv6 = pma->GetIPv6();
		#endif
					m_nAllocPort = pma->GetPort();
				}
				const CSourceAddress *psa = msg.GetSourceAddress();
				if(psa)
				{
		#ifndef IPV6_SUPPORT
					m_nNATIP = psa->GetIPV4();
		#else
					m_nNATIP6 = psa->GetIPv6();
		#endif
					m_nNATPort = psa->GetPort();
				}
				if(msg.GetLifeTime())
					m_nLifeTime = msg.GetLifeTime()->GetLifeTime();
				else
					m_nLifeTime = livetime;
				
				m_bAllocateOK = true;
				timeval tv;
				gettimeofday(&tv,0);
				m_nNextTime = tv.tv_sec*1000 + tv.tv_usec/1000 + m_nLifeTime*1000*2/3;
				m_nTryCount=1;
				m_bAllocateRelay = TRUE;
				return true;
			}
			else
			{
				return false;
			}
		}		
	}
	return false;	
}

bool CTurnClient::AllocateChannelRequest()
{
	if(m_s == INVALID_SOCKET)
		return false;
	sockaddr_in addr;
//	printf("%s\r\n",m_strTempUserName.c_str());
	char sha[32];
	CTurnMessage msg;
	msg.SetCommand(TURN_COMMAND_ALLOCATE_CHANNEL_REQUEST);
	msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
	msg.AddBandwidth(new CBandwidth(384));
	//msg.AddLifeTime(new CLifeTime(livetime));
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	char buf[1024];
	int n,i;
	//memset(buf,0,1024);
	n = msg.Encode(buf,1024) - 36;
	memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());
		
	if(ComputeMD5(buf,n+m_strTempPassword.length(),sha) == false)
	{	
		return false;
	}

	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	n = msg.Encode(buf,1024);
	if(n <= 0)
	{	
		return false;
	}
#ifdef IPV6_SUPPORT
	struct addrinfo aiHint, *res;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_flags = AI_NUMERICHOST;
	int error;
	error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
	if(error)
		return false;
	SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
#endif
	for(i=0;i<TRY_TIMES;i++)
	{
#ifndef IPV6_SUPPORT
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
		addr.sin_port = htons(m_nServerPort);
		int len = sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
#else
		int len = sendto(m_s,buf,n,0,(sockaddr *)res->ai_addr,res->ai_addrlen);

#endif
		if(len != n)
		{
		#ifdef IPV6_SUPPORT
			freeaddrinfo(res);
		#endif
			return false;
		}
		fd_set rset;
		FD_ZERO(&rset);
		FD_SET(m_s,&rset);
		timeval tv;
		tv.tv_sec = m_nDeltaTime/1000;
		tv.tv_usec = (m_nDeltaTime%1000)*1000;
		n = select(m_s+1,&rset,NULL,NULL,&tv);
		if(n == 0)
		{	
			continue;
		}
		else if(n < 0)
		{
		#ifdef IPV6_SUPPORT
			freeaddrinfo(res);
		#endif
			return false;
		}
		else
			break;
	}
	#ifdef IPV6_SUPPORT
		freeaddrinfo(res);
	#endif
	if(i >= TRY_TIMES && n <= 0)
		return false;
#ifndef IPV6_SUPPORT
	socklen_t socklen = sizeof(addr);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&addr,&socklen);
#else
	struct sockaddr_storage ss;
	int sslen = sizeof(ss);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif
	if(n > 0)
	{
		if(msg.Parse(buf,n))
		{
			const CMappedAddress *pma = msg.GetMappedAddress();
			if(pma)
			{
			#ifndef IPV6_SUPPORT
				m_nChannelIP = pma->GetIPV4();
			#else
				m_nChannelIP6 = pma->GetIPv6();
			#endif
				m_nChannelPort = pma->GetPort();
			}
			const CChannelID *pch = msg.GetChannelID();
			if(pch)
				m_strChannelID = pch->GetChannelID();
			/*
			const CSourceAddress *psa = msg.GetSourceAddress();
			if(psa)
			{
				m_nNATIP = psa->GetIPV4();
				m_nNATPort = psa->GetPort();
			}
			*/
		}
	}
	return true;	
}

bool CTurnClient::ReleaseChannelRequest(const char *pchid)
{
	if(m_s == INVALID_SOCKET)
		return false;
	sockaddr_in addr;
//	printf("%s\r\n",m_strTempUserName.c_str());
	char sha[32];
	CTurnMessage msg;
	msg.SetCommand(TURN_COMMAND_RELEASE_CHANNEL_REQUEST);
	msg.AddUserName(new CUserName(m_strTempUserName.c_str()));	
	msg.AddChannelID(new CChannelID(pchid));
	//msg.AddLifeTime(new CLifeTime(livetime));
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	char buf[1024];
	int n;
	//memset(buf,0,1024);
	n = msg.Encode(buf,1024) - 36;
	memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());
		
	if(ComputeMD5(buf,n+m_strTempPassword.length(),sha) == false)
	{	
		return false;
	}

	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	n = msg.Encode(buf,1024);
	if(n <= 0)
	{	
		return false;
	}
#ifndef IPV6_SUPPORT
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
	addr.sin_port = htons(m_nServerPort);
	int len = sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
#else
	struct addrinfo aiHint, *res;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_flags = AI_NUMERICHOST;
	int error;
	error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
	if(error)
		return false;
	SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
	int len = sendto(m_s, buf, n, 0, (sockaddr *)res->ai_addr, res->ai_addrlen);
	freeaddrinfo(res);
#endif
	if(len != n)
	{	
		return false;
	}
	fd_set rset;
	FD_ZERO(&rset);
	FD_SET(m_s,&rset);
	timeval tv;
	tv.tv_sec = m_nDeltaTime/1000;
	tv.tv_usec = (m_nDeltaTime%1000)*1000;
	n = select(m_s+1,&rset,NULL,NULL,&tv);
	if(n <= 0)
	{	
		return false;	
	}
#ifndef IPV6_SUPPORT
	socklen_t socklen = sizeof(addr);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&addr,&socklen);
#else
	struct sockaddr_storage ss;
	int sslen = sizeof(ss);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif
	if(n > 0)
	{
		if(msg.Parse(buf,n))
		{
			return (msg.GetCommand() == TURN_COMMAND_RELEASE_CHANNEL_RESPONSE);
		}
		else
			return false;
	}
	return false;	
}

bool CTurnClient::SendDataRequest()
{
	if(m_s == INVALID_SOCKET)
		return false;
	sockaddr_in addr;
	char sha[32];
	CTurnMessage msg;
	msg.SetCommand(TURN_COMMAND_SEND_REQUEST);
	msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
//	msg.AddBandwidth(new CBandwidth(384));
//	msg.AddLifeTime(new CLifeTime(0));
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	char buf[1024];
	int n;
	//memset(buf,0,1024);
	n = msg.Encode(buf,1024) - 36;
	memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());
		
	if(ComputeMD5(buf,n+m_strTempPassword.length(),sha) == false)
	{	
		return false;
	}

	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	n = msg.Encode(buf,1024);
	if(n <= 0)
	{	
		return false;
	}
#ifndef IPV6_SUPPORT
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
	addr.sin_port = htons(m_nServerPort);
	int len = sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
#else
	struct addrinfo aiHint, *res;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_flags = AI_NUMERICHOST;
	int error;
	error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
	if(error)
		return false;
	SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
	int len = sendto(m_s, buf, n, 0, (sockaddr *)res->ai_addr, res->ai_addrlen);
	freeaddrinfo(res);
#endif
	if(len != n)
	{	
		//n = WSAGetLastError();
		return false;
	}
	fd_set rset;
	FD_ZERO(&rset);
	FD_SET(m_s,&rset);
	timeval tv;
	tv.tv_sec = m_nDeltaTime/1000;
	tv.tv_usec = (m_nDeltaTime%1000)*1000;
	n = select(m_s+1,&rset,NULL,NULL,&tv);
	if(n <= 0)
	{
		return false;
	}
#ifndef IPV6_SUPPORT
	socklen_t socklen = sizeof(addr);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&addr,&socklen);
#else
	struct sockaddr_storage ss;
	int sslen = sizeof(ss);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif
	if(n > 0)
	{
		if(msg.Parse(buf,n))
		{
			const CMappedAddress *pma = msg.GetMappedAddress();
			if(pma)
			{
	#ifndef IPV6_SUPPORT
				m_nAllocIP = pma->GetIPV4();
	#else
				m_AllocIPv6 = pma->GetIPv6();
	#endif
				m_nAllocPort = pma->GetPort();
			}
		}
	}
	return true;
}
void CTurnClient::GetPayload(char *pdata,int len,char *pbuf,int &length)
{
	int n;
	unsigned char *p = (unsigned char *)pdata;
	int command = ntohs(*(unsigned short *)p);
	p+=2;
	n = ntohs(*(unsigned short *)p);
	if(n + 20 == len)
	{
		unsigned long magic = htonl(0x72c64bc6);
		if(memcmp(&pdata[24],&magic,4) == 0)
		{
			CTurnMessage msg;
			if(msg.Parse(pdata,len))
			{
				const CData *pd = msg.GetDATA();
				if(pd && pd->GetData() && pd->GetLength()>0)
				{
					memcpy(pbuf,pd->GetData(),pd->GetLength());
					length = pd->GetLength();
					const CSourceAddress *psa = msg.GetSourceAddress();
					if(psa)
					{
				#ifndef IPV6_SUPPORT
						m_nSourceIP = psa->GetIPV4();
				#else
						m_nSourceIP6 = psa->GetIPv6();
				#endif
						m_nSourcePort = psa->GetPort();
					}
					else
					{
				#ifndef IPV6_SUPPORT
						m_nSourceIP = 0;
				#else
						//IN6_SET_ADDR_UNSPECIFIED(&m_nSourceIP6);
						memset(&m_nSourceIP6, 0, sizeof(struct in6_addr));
				#endif
						m_nSourcePort = 0;
					}
				}
				else
					length = 0;
				return;
			}
		}
	}
	memcpy(pbuf,pdata,len);
	length = len;	
}

bool CTurnClient::StartRecord(const char *prid)
{
	if(m_s == INVALID_SOCKET)
		return false;
	sockaddr_in addr;
	
	char sha[32];
	CTurnMessage msg;
	msg.SetCommand(TURN_COMMAND_START_RECORD_REQUEST);
	msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
	msg.AddVideoFormat(new CVideoformat(m_nVideoFormat));
	msg.AddVideoFrameRate(new CVideoframerate(m_nfps));
	msg.AddVideoWidth(new CVideowidth(m_nVideoWidth));
	msg.AddVideoHeight(new CVideoheight(m_nVideoHeight));
	msg.AddRecordID(new CRecordID(prid));
	msg.AddOwnerID(new COwnerID(m_strOwner.c_str()));
	msg.AddStartTime(new CStartTime(m_nStartTime));
	msg.AddStopTime(new CStopTime(m_nStopTime));
	msg.AddSubTitle(new CSubTitle(m_strSubTitle.c_str()));
	msg.AddSubTitlePos(new CSubTitlePos(m_nSubTitlePos));
	msg.AddTimeTitlePos(new CTimeTitlePos(m_nTimeTitlePos));
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	char buf[1024];
	int n,i;
	//memset(buf,0,1024);
	n = msg.Encode(buf,1024) - 36;
	memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());
		
	if(ComputeMD5(buf,n+m_strTempPassword.length(),sha) == false)
	{	
		return false;
	}

	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	n = msg.Encode(buf,1024);
	if(n <= 0)
	{	
		return false;
	}
#ifdef IPV6_SUPPORT
	struct addrinfo aiHint, *res;
	memset(&aiHint, 0, sizeof(aiHint));
	aiHint.ai_family = AF_UNSPEC;
	aiHint.ai_flags = AI_NUMERICHOST;
	int error;
	error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
	if(error)
		return false;
	SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
#endif

	for(i=0;i<TRY_TIMES;i++)
	{
	#ifndef IPV6_SUPPORT
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
		addr.sin_port = htons(m_nServerPort);
		int len = sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
		if(len != n)
		{
			return false;
		}
	#else
		int len = sendto(m_s, buf, n, 0, (sockaddr *)res->ai_addr, res->ai_addrlen);
	
		if(len != n)
		{
			freeaddrinfo(res);
			return false;
		}
	#endif
		fd_set rset;
		FD_ZERO(&rset);
		FD_SET(m_s,&rset);
		timeval tv;
		tv.tv_sec = m_nDeltaTime/1000;
		tv.tv_usec = (m_nDeltaTime%1000)*1000;
		n = select(m_s+1,&rset,NULL,NULL,&tv);
		if(n == 0)
		{	
			continue;
		}
		else if(n < 0)
		{
		#ifdef IPV6_SUPPORT
			freeaddrinfo(res);
		#endif
			return false;
		}
		else
			break;
	}
	#ifdef IPV6_SUPPORT
		freeaddrinfo(res);
	#endif
	if(i >= TRY_TIMES && n <= 0)
		return false;
#ifndef IPV6_SUPPORT
	socklen_t socklen = sizeof(addr);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&addr,&socklen);
#else
	struct sockaddr_storage ss;
	int sslen = sizeof(ss);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif
	if(n > 0)
	{
		if(msg.Parse(buf,n))
		{
			return (msg.GetCommand() == TURN_COMMAND_START_RECORD_RESPONSE);	
		}
	}
	return false;
}

bool CTurnClient::StopRecord(const char *prid)
{
	if(m_s == INVALID_SOCKET)
		return true;
	sockaddr_in addr;
	
	char sha[32];
	CTurnMessage msg;
	msg.SetCommand(TURN_COMMAND_STOP_RECORD_REQUEST);
	msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
	//msg.AddVideoFormat(new CVideoformat(m_nVideoFormat));
	//msg.AddVideoFrameRate(new CVideoframerate(m_nfps));
	//msg.AddVideoWidth(new CVideowidth(m_nVideoWidth));
	//msg.AddVideoHeight(new CVideoheight(m_nVideoHeight));
	msg.AddRecordID(new CRecordID(prid));
	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	char buf[1024];
	int n,i;
	//memset(buf,0,1024);
	n = msg.Encode(buf,1024) - 36;
	memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());
		
	if(ComputeMD5(buf,n+m_strTempPassword.length(),sha) == false)
	{	
		return false;
	}

	msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
	n = msg.Encode(buf,1024);
	if(n <= 0)
	{	
		return false;
	}
	#ifdef IPV6_SUPPORT
		struct addrinfo aiHint, *res;
		memset(&aiHint, 0, sizeof(aiHint));
		aiHint.ai_family = AF_UNSPEC;
		aiHint.ai_flags = AI_NUMERICHOST;
		int error;
		error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
		if(error)
			return false;
		SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
	#endif
	for(i=0;i<TRY_TIMES;i++)
	{
#ifndef IPV6_SUPPORT
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
		addr.sin_port = htons(m_nServerPort);
		int len = sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
		if(len != n)
		{	
			return false;
		}
#else
		int len = sendto(m_s, buf, n, 0, (sockaddr *)res->ai_addr, res->ai_addrlen);
		if(len != n)
		{
			freeaddrinfo(res);
			return false;
		}
#endif

		fd_set rset;
		FD_ZERO(&rset);
		FD_SET(m_s,&rset);
		timeval tv;
		tv.tv_sec = m_nDeltaTime/1000;
		tv.tv_usec = (m_nDeltaTime%1000)*1000;
		n = select(m_s+1,&rset,NULL,NULL,&tv);
		if(n == 0)
		{	
			continue;
		}
		else if(n < 0)
			return false;
		else
			break;
	}
	#ifdef IPV6_SUPPORT
		freeaddrinfo(res);
	#endif
	if(i >= TRY_TIMES && n <= 0)
		return false;
#ifndef IPV6_SUPPORT
	socklen_t socklen = sizeof(addr);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&addr,&socklen);
#else
	struct sockaddr_storage ss;
	int sslen = sizeof(ss);
	n = recvfrom(m_s,buf,1024,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif

	if(n > 0)
	{
		if(msg.Parse(buf,n))
		{
			if(msg.GetCommand() == TURN_COMMAND_STOP_RECORD_RESPONSE)
				return true;
			else
				return true;
		}
	}
	return false;
}

bool CTurnClient::ProcessTimeout()
{
	//if(m_bAllocateOK == false)
	//	return;
	char buf[1024];
	timeval tv;
	unsigned long l;
	int n;
	sockaddr_in addr;	
	char sha[32];
	CTurnMessage msg;
	if(m_bAllocateOK == false || m_nTryCount > 8)
		return false;
	gettimeofday(&tv,NULL);
	
#ifdef WIN32		
	ioctlsocket(m_s,FIONREAD,&l);
#else
	ioctl(m_s,FIONREAD,&l);
#endif
	if(l > 0)
	{
#ifndef IPV6_SUPPORT
		socklen_t socklen = sizeof(addr);
		n = recvfrom(m_s,buf,1024,0,(sockaddr *)&addr,&socklen);
#else
		struct sockaddr_storage ss;
		int sslen = sizeof(ss);
		n = recvfrom(m_s,buf,1024,0,(sockaddr *)&ss,(socklen_t *)&sslen);
#endif
		if(n > 0)
		{
			if(msg.Parse(buf,n))
			{
				
				if(m_bAllocate && msg.GetCommand() == TURN_COMMAND_ALLOCATE_RESPONSE)
				{
					const CMappedAddress *pma = msg.GetMappedAddress();
					if(pma)
					{
#ifndef IPV6_SUPPORT
						m_nAllocIP = pma->GetIPV4();
#else
						m_AllocIPv6 = pma->GetIPv6();
#endif
						m_nAllocPort = pma->GetPort();
					}
					const CSourceAddress *psa = msg.GetSourceAddress();
					if(psa)
					{
#ifndef IPV6_SUPPORT
						m_nNATIP = psa->GetIPV4();
#else
						m_nNATIP6 = psa->GetIPv6();
#endif
						m_nNATPort = psa->GetPort();
					}
					if(msg.GetLifeTime())
						m_nLifeTime = msg.GetLifeTime()->GetLifeTime();
					
					m_nNextTime = tv.tv_sec*1000 + tv.tv_usec/1000 + m_nLifeTime*1000*2/3;
					m_nTryCount = 0;
				}
				else if(m_bAllocateRelay && msg.GetCommand() == TURN_COMMAND_ALLOCATE_RELAY_RESPONSE)
				{
					const CMappedAddress *pma = msg.GetMappedAddress();
					if(pma)
					{
#ifndef IPV6_SUPPORT
						m_nAllocIP = pma->GetIPV4();
#else
						m_AllocIPv6 = pma->GetIPv6();
#endif
						m_nAllocPort = pma->GetPort();
					}
					const CSourceAddress *psa = msg.GetSourceAddress();
					if(psa)
					{
#ifndef IPV6_SUPPORT
						m_nNATIP = psa->GetIPV4();
#else
						m_nNATIP6 = psa->GetIPv6();
#endif
						m_nNATPort = psa->GetPort();
					}
					if(msg.GetLifeTime())
						m_nLifeTime = msg.GetLifeTime()->GetLifeTime();
					
					m_nNextTime = tv.tv_sec*1000 + tv.tv_usec/1000 + m_nLifeTime*1000*2/3;
					m_nTryCount = 0;
				}
			}	
		}
	}
	if(m_nNextTime > 0 && m_nNextTime <= tv.tv_sec*1000 + tv.tv_usec/1000)
	{
		msg.Clear();
		if(m_bAllocate)
		{
			msg.SetCommand(TURN_COMMAND_ALLOCATE_REQUEST);
			msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
			msg.AddBandwidth(new CBandwidth(384));
			msg.AddLifeTime(new CLifeTime(m_nLifeTime));
			msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));		
			//memset(buf,0,1024);
			n = msg.Encode(buf,1024) - 36;
			memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());		
			ComputeMD5(buf,n+m_strTempPassword.length(),sha);
			
			msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
			n = msg.Encode(buf,1024);
#ifndef IPV6_SUPPORT
			addr.sin_family = AF_INET;
			addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
			addr.sin_port = htons(m_nServerPort);
			sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
#else
			struct addrinfo aiHint, *res;
			memset(&aiHint, 0, sizeof(aiHint));
			aiHint.ai_family = AF_UNSPEC;
			aiHint.ai_flags = AI_NUMERICHOST;
			int error;
			error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
			if(error)
				return false;
			SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
			int len = sendto(m_s, buf, n, 0, (sockaddr *)res->ai_addr, res->ai_addrlen);
			freeaddrinfo(res);
#endif
			if((200<<m_nTryCount) > 4000)
			{
				m_nNextTime += 4000;
			}
			else
			{
				m_nNextTime += (200<<m_nTryCount);
			}
		}
		if(m_bAllocateRelay)
		{
			msg.SetCommand(TURN_COMMAND_ALLOCATE_RELAY_REQUEST);
			msg.AddUserName(new CUserName(m_strTempUserName.c_str()));
			msg.AddBandwidth(new CBandwidth(384));
			msg.AddLifeTime(new CLifeTime(m_nLifeTime));
			msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));		
			//memset(buf,0,1024);
			n = msg.Encode(buf,1024) - 36;
			memcpy(&buf[n],m_strTempPassword.c_str(),m_strTempPassword.length());		
			ComputeMD5(buf,n+m_strTempPassword.length(),sha);
			
			msg.AddMessageIntegrity(new CMessageIntegrity(sha,32));
			n = msg.Encode(buf,1024);
#ifndef IPV6_SUPPORT
			addr.sin_family = AF_INET;
			addr.sin_addr.s_addr = inet_addr(m_strServerIP.c_str());
			addr.sin_port = htons(m_nServerPort);
			sendto(m_s,buf,n,0,(sockaddr *)&addr,sizeof(addr));
#else
			struct addrinfo aiHint, *res;
			memset(&aiHint, 0, sizeof(aiHint));
			aiHint.ai_family = AF_UNSPEC;
			aiHint.ai_flags = AI_NUMERICHOST;
			int error;
			error = getaddrinfo(m_strServerIP.c_str(), NULL, &aiHint, &res);
			if(error)
				return false;
			SS_GET_PORT(res->ai_addr) = htons(m_nServerPort);
			int len = sendto(m_s, buf, n, 0, (sockaddr *)res->ai_addr, res->ai_addrlen);
			freeaddrinfo(res);
#endif
			if((200<<m_nTryCount) > 4000)
			{
				m_nNextTime += 4000;
			}
			else
			{
				m_nNextTime += (200<<m_nTryCount);
			}
		}

		m_nTryCount++;
	}	
	return true;
}
